/******************************************************************
* Copyright (C), 2005-2007, HISILICON Tech. Co., Ltd.             *
*                                                                 *
* File name: Pl110_clcdc.c                                        *
*                                                                 *
* Description:                                                    *
*     The CLCDC driver C file for public use.                     *
*                                                                 *
* Author:  H55798                                                 *
*                                                                 *
* Version: v0.1                                                   *
*                                                                 *
* Date:    2007.04.20                                             *
*                                                                 *
* History:                                                        *
*                                                                 *
*   1. Date:                                                      *
*      Author:                                                    *
*      Modification:                                              *
*   2. ...                                                        *
*******************************************************************/

#include <windows.h>
#include <Dbgapi.h>
#include <Ceddk.h>
#include "uldrui.h"
#include "hisi6810_gpio.h"

#ifdef __cplusplus
extern "C" { /* allow C++ to use these headers */
#endif /* __cplusplus */

#ifndef DMDO_0
/* rotation angle for screen rotation */
#define DMDO_0      0
#define DMDO_90     1
#define DMDO_180    2
#define DMDO_270    4
#define DMDO_DEFAULT DMDO_0
#endif

/*
 * Define LCD driver registers
 */
typedef struct
{
    volatile ULONG *    pPwmReg;
    
    /*define LCD display related parameters*/
    UINT32              width;
    UINT32              height;
    UINT32              stride;
    INT32               ulDispBpp;
    DWORD               orientation;
    UINT32              ulFrameBufferSize;
    UINT32              ulFrameBufferPhyAddr;
    UINT32              ulFrameBufferVirtualAddr;
      
}DISPLAY_T, *P_DISPLAY_T;

/************************************************
 * 
 * Functions declare
 *
 ************************************************/
DISPLAY_T   g_display;

static void  BacklightTurnOnOff(volatile ULONG* pPwmReg, bool isOn)
{
    pPwmReg[PWM_OUTA_EN_OFFSET >> 2]   = isOn;
    pPwmReg[PWM_OUTA_DIV_OFFSET >> 2]  = PWM_OUTA_DIV;
    pPwmReg[PWM_OUTA_WIDE_OFFSET >> 2] = PWM_OUTA_DIV >> 1;
}

/*****************************************************
 * Function: MapAddress
 * Description: map physical address into GWES address space.
 * Calls: 
 * Called by: 
 * Table Access: list the table you will use. 
 * Table Update: list the table which you will update.
 * Input: NONE
 * Output: NONE
 * Return: NONE
 * Others: NONE
 ****************************************************/

BOOL MapAddress(void)
{
    PHYSICAL_ADDRESS RegPA;

    RegPA.QuadPart = PWM_BASE_ADDRESS;
    if (NULL == (g_display.pPwmReg = (volatile ULONG *)HiMmMapIoSpace(RegPA, 0x10000, FALSE)))
    {
        RETAILMSG(1, (TEXT("m_pCLCDCREG is not mapped.\n\r")));
        return FALSE;
    }
    
    g_display.ulFrameBufferVirtualAddr  = (DWORD)VirtualAlloc(NULL, FRAME_BUFFER_SIZE, MEM_RESERVE, PAGE_NOACCESS);

    if (NULL == g_display.ulFrameBufferVirtualAddr)
    {
        RETAILMSG(1, (TEXT("Video Memory VA is not allocated.\n\r")));
       return FALSE;
    }

    if (!VirtualCopy((PVOID)g_display.ulFrameBufferVirtualAddr , (LPVOID)(g_display.ulFrameBufferPhyAddr >> 8), 
        FRAME_BUFFER_SIZE, PAGE_READWRITE | PAGE_PHYSICAL | PAGE_NOCACHE))
    {
        RETAILMSG(1, (TEXT("Frame buffer is not VirtualCopied\n\r")));
        return FALSE;
    }

    return TRUE;  
}

void UnMapAddress(void)
{    
    if (g_display.pPwmReg)
    {
        HiMmUnmapIoSpace((PVOID)g_display.pPwmReg, 0x10000);
        g_display.pPwmReg = NULL;
    }
 
    if (g_display.ulFrameBufferVirtualAddr )
    {
        (void)VirtualFree((PVOID)g_display.ulFrameBufferVirtualAddr , 0, MEM_RELEASE);
        g_display.ulFrameBufferVirtualAddr  = NULL;
    }   
}


#ifdef __cplusplus
}
#endif /* __cplusplus */


/*****************************************************
 *  Interface function Definition
 ****************************************************/

BOOL
InitDisplay(
    DWORD width,
    DWORD height,
    DWORD bpp,
    DWORD orientation
    )
{
    RETAILMSG(TRUE, (L" !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!InitDisplay"));
    // Clear
    memset(&g_display, 0, sizeof(g_display));

    // We support only 16 bpp...
    if (bpp != 16)
    {
        RETAILMSG(TRUE, (L"ERROR: InitDisplay: "
            L"Display doesn't support %d bpp\r\n", bpp
            ));
        return  FALSE;
    }
    
    if ((orientation != DMDO_0) && (orientation != DMDO_90) && (orientation != DMDO_180) && (orientation != DMDO_270))
    {
        RETAILMSG(TRUE, (L"ERROR: InitDisplay: "
            L"Display doesn't suppor orientation = %d \r\n",
            orientation
            ));
        return  FALSE;
    }
   
    g_display.width = width;
    g_display.height = height;
    g_display.stride = (g_display.width * bpp) >> 3;
    g_display.orientation = orientation;
    g_display.ulFrameBufferSize = ((g_display.stride) * (g_display.width * g_display.height));
    g_display.ulFrameBufferPhyAddr = FRAME_BUFFER_PA;
    
    if(FALSE == MapAddress())
    {
        UnMapAddress();
        return FALSE;
    }

    return  TRUE;
}

BOOL DeinitDisplay()
{
    RETAILMSG(TRUE, (L" !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!DeinitDisplay"));
    
    BacklightTurnOnOff(g_display.pPwmReg, FALSE);
    
    UnMapAddress();
    
    return TRUE;
}

//------------------------------------------------------------------------------

BOOL BltRect(RECT rc, DWORD stride, VOID *pBuffer)
{
    volatile USHORT *pFrame = (USHORT *)(g_display.ulFrameBufferVirtualAddr);
    DWORD screenWidth = g_display.width;
    DWORD screenHeight = g_display.height;
    USHORT *pData = (USHORT*)pBuffer;
    LONG xs, ys, xt, yt;
    
    if(pData == NULL)
    {
        return FALSE;
    }
    // Convert stride from bytes to words
    stride /= sizeof(USHORT);
    switch(g_display.orientation)
    {
        case DMDO_0://0
            for (yt = rc.top, ys = 0; yt < rc.bottom; yt++, ys++)
            {
                for (xt = rc.left, xs = 0; xt < rc.right; xt++, xs++)
                {
                    pFrame[yt * screenWidth + xt] = pData[ys * stride + xs];
                }
            }
            break;

        case DMDO_180://180
            for (yt = rc.bottom, ys = 0; yt > ((long)screenHeight-rc.bottom); yt--, ys++)
            {
                for (xt = screenWidth-rc.left, xs = 0; xt > ((long)screenWidth-rc.right); xt--, xs++)
                {
                    pFrame[yt * screenWidth + xt] = pData[ys * stride + xs];
                }
            }
            break;

        case DMDO_90://90
             for (xt = rc.top, xs = 0; xt < rc.bottom; xt++, xs++)
             {
                for (yt = screenHeight - rc.left, ys = 0; yt > ((long)screenHeight - rc.right); yt--, ys++)
                {
                    pFrame[yt * screenWidth + xt] = pData[ys * stride + xs];
                }
             }
            break;
            
        case DMDO_270://270
            for (xt = screenWidth-rc.top, xs = 0; xt > ((long)screenWidth-rc.bottom); xt--, xs++)
            {
                for (yt = rc.left, ys = 0; yt < rc.right; yt++, ys++)
                {
                    pFrame[yt * screenWidth + xt] = pData[ys * stride + xs];
                }
            }
            break;
            
        default:
            return FALSE;
            break;
    }
    return TRUE;
}

